package com.campus.delivery.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.campus.common.bean.common.Resp;
import com.campus.common.constants.GlobalConstant;
import com.campus.delivery.entity.Delivery;
import com.campus.delivery.entity.DeliveryUser;
import com.campus.delivery.mapper.DeliveryMapper;
import com.campus.delivery.mapper.DeliveryUserMapper;
import com.campus.delivery.vo.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
public class WechatAuthService {
    private static final String GET_ACCESS_TOKEN_URL =
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    private static final String GET_PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";

    @Value("${wechat.appid}")
    private String appid;

    @Value("${wechat.secret}")
    private String secret;

    @Autowired
    private DeliveryUserMapper deliveryUserMapper;

    @Autowired
    private RedisService redisService;

    // accessToken有效期（秒）
    private static final long ACCESS_TOKEN_EXPIRE = 1800; // 30分钟
    // refreshToken有效期（秒）
    private static final long REFRESH_TOKEN_EXPIRE = 7 * 86400L; // 7天
    @Autowired
    private DeliveryMapper deliveryMapper;

    /**
     * 微信小程序静默登录
     * @param code 微信登录code
     * @return Resp 包含accessToken、refreshToken和用户信息
     */
    public Resp wxLogin(String code) {
        String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                appid, secret, code);

        String responseBody = HttpUtil.get(url);
        JSONObject response = JSONUtil.parseObj(responseBody);
        if (response == null || response.containsKey("errcode")) {
            return Resp.error("微信登录失败: " + (response != null ? response.getStr("errmsg") : "未知错误"));
        }

        String openid = response.getStr("openid");
        String sessionKey = response.getStr("session_key");

        // 查询或创建配送员用户
        DeliveryUser user = deliveryUserMapper.selectOne(Wrappers.lambdaQuery(DeliveryUser.class).eq(DeliveryUser::getOpenid, openid));
        if (user == null) {
            user = new DeliveryUser();
            user.setOpenid(openid);
            deliveryUserMapper.insert(user);
        }

        // 生成accessToken和refreshToken
        String accessToken = generateToken(user, "access");
        String refreshToken = generateToken(user, "refresh");

        // 存入redis
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfoVo);
        userInfoVo.setToken(accessToken);
        redisService.set(accessToken, JSON.toJSONString(userInfoVo), ACCESS_TOKEN_EXPIRE);
        redisService.set(refreshToken, JSON.toJSONString(userInfoVo), REFRESH_TOKEN_EXPIRE);

        //根据用户ID查询配送员ID
        Delivery delivery = deliveryMapper.selectOne(Wrappers.lambdaQuery(Delivery.class).eq(Delivery::getDeliveryUserId, user.getId()));

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        result.put("userInfo", userInfoVo);
        if (delivery != null) {
            result.put("deliveryId", delivery.getId());
        }
        
        // 检查是否需要获取顾客端openid
        if (StringUtils.isBlank(user.getCustomerOpenid())) {
            result.put("needCustomerOpenid", true);
            result.put("deliveryOpenid", user.getOpenid());
            log.info("配送员{}缺少顾客端openid，需要跳转获取", user.getOpenid());
        } else {
            result.put("needCustomerOpenid", false);
        }
        
        return Resp.success(result);
    }

    /**
     * 刷新token
     * @param refreshToken refreshToken
     * @return Resp 新accessToken和refreshToken
     */
    public Resp refreshToken(String refreshToken) {
        // 校验refreshToken
        String userInfoStr = redisService.get(refreshToken);
        if (userInfoStr == null) {
            return Resp.error("refreshToken无效或已过期");
        }
        UserInfoVo userInfoVo = JSON.parseObject(userInfoStr, UserInfoVo.class);
        // 生成新accessToken和refreshToken
        DeliveryUser user = new DeliveryUser();
        BeanUtils.copyProperties(userInfoVo, user);
        String newAccessToken = generateToken(user, "access");
        String newRefreshToken = generateToken(user, "refresh");
        // 存入redis
        userInfoVo.setToken(newAccessToken);
        redisService.set(newAccessToken, JSON.toJSONString(userInfoVo), ACCESS_TOKEN_EXPIRE);
        redisService.set(newRefreshToken, JSON.toJSONString(userInfoVo), REFRESH_TOKEN_EXPIRE);
        // 删除旧refreshToken
        redisService.remove(refreshToken);
        // 返回新token
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", newAccessToken);
        result.put("refreshToken", newRefreshToken);
        return Resp.success(result);
    }

    /**
     * 生成token
     */
    private String generateToken(DeliveryUser user, String type) {
        return MD5.create().digestHex((user.getOpenid() != null ? user.getOpenid() : "merchant") + type + UUID.randomUUID().toString() + DateTime.now().toString("yyyyMMddHHmmss"));
    }


    /**
     * 获取小程序全局唯一后台接口调用凭据AccessToken
     * @return
     */
    public String getAccessToken() {
        String accessTokenInRedis = redisService.get(GlobalConstant.WECHAT_ACCESS_TOKEN + appid);

        if(StringUtils.isNotBlank(accessTokenInRedis)){
            return accessTokenInRedis;
        }

        String url = String.format(GET_ACCESS_TOKEN_URL, appid, secret);
        String result = HttpUtil.get(url, StandardCharsets.UTF_8);

        log.info("获取accessToken接口返回结果：{}", result);

        JSONObject resultJO = JSONUtil.parseObj(result);

        String accessToken = resultJO.getStr("access_token");
        Long expiresIn = resultJO.getLong("expires_in");

        //TODO 保存到redis
        if(StringUtils.isNotBlank(accessToken)){
            redisService.set(GlobalConstant.WECHAT_ACCESS_TOKEN + appid, accessToken, expiresIn-100);
        }

        return accessToken;
    }


    public String getWechatPhoneNumber(String code) {
        String url = String.format(GET_PHONE_NUMBER_URL, getAccessToken());
        Map<String, Object> map = new HashMap<>();
        map.put("code", code);
        String result = HttpUtil.post(url, JSONUtil.toJsonStr(map));
        log.info("获取手机号接口返回结果：{}", result);
        if (result != null) {
            JSONObject resultJO = JSONUtil.parseObj(result);
            int errcode = resultJO.getInt("errcode");
            if (errcode != 0) {
                String errmsg = resultJO.getStr("errmsg");
                log.error("获取手机号失败：{}", errmsg);
                return null;
            }
            JSONObject phoneInfo = resultJO.getJSONObject("phone_info");
            String phoneNumber = phoneInfo.getStr("phoneNumber");

            return phoneNumber;
        }
        return null;
    }
}